/' Copyright (c) 2007 Scott Lembcke
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 '/

''' Constant for the zero vector.
#define cpvzero	type<cpVect> (0, 0)

''' Convenience constructor for cpVect structs.
function cpv ( byval x as cpFloat, byval y as cpFloat ) as cpVect
    return type<cpVect> ( x, y )
end function

'' non-inlined functions
declare function cpvlength cdecl alias "cpvlength" ( byval as cpVect ) as cpFloat
declare function cpvslerp cdecl alias "cpvslerp" ( byval as cpVect, byval as cpVect, byval as cpFloat ) as cpVect
declare function cpvslerpconst cdecl alias "cpvslerp" ( byval as cpVect, byval as cpVect, byval as cpFloat ) as cpVect
declare function cpvforangle cdecl alias "cpvforangle" ( byval as cpFloat ) as cpVect	'' Radians to normalized vector
declare function cpvtoangle cdecl alias "cpvtoangle" ( byval as cpVect ) as cpFloat '' vector to radians
declare function cpvstr cdecl alias "cpvstr" ( byval as cpVect ) as zstring ptr '' string representation of a vector

''' Check if two vectors are equal. (Be careful when comparing floating point numbers!)
function cpveql( byval v1 as const cpVect, byval v2 as const cpVect ) as cpBool
	return (v1.x = v2.x) and (v1.y = v2.y)
end function

function cpvadd ( byval v1 as cpVect, byval v2 as cpVect ) as cpVect
    return cpv(v1.x+v2.x, v1.y+v2.y)
end function

function cpvneg ( byval v as cpVect ) as cpVect
    return cpv(-v.x, -v.y)
end function

function cpvsub ( byval v1 as cpVect, byval v2 as cpVect ) as cpVect
    return cpv(v1.x-v2.x, v1.y-v2.y)
end function

function cpvmult ( byval v as cpVect, byval s as cpFloat ) as cpVect
    return cpv(v.x*s, v.y*s)
end function

function cpvdot ( byval v1 as cpVect, byval v2 as cpVect ) as cpFloat
    return v1.x*v2.x + v1.y*v2.y
end function

function cpvcross ( byval v1 as cpVect, byval v2 as cpVect ) as cpFloat
    return v1.x*v2.y - v1.y*v2.x
end function

function cpvperp ( byval v as cpVect ) as cpVect
    return cpv(-v.y, v.x)
end function

function cpvrperp ( byval v as cpVect ) as cpVect
    return cpv(v.y, -v.x)
end function

function cpvproject ( byval v1 as cpVect, byval v2 as cpVect ) as cpVect
    return cpvmult(v2, cpvdot(v1, v2)/cpvdot(v2, v2))
end function

function cpvrotate ( byval v1 as cpVect, byval v2 as cpVect ) as cpVect
	return cpv(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x)
end function

function cpvunrotate ( byval v1 as cpVect, byval v2 as cpVect ) as cpVect
	return cpv(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y)
end function

function cpvlengthsq( byval v as cpVect ) as cpFloat
	return cpvdot( v, v )
end function

function cpvlerp( byval v1 as cpVect, byval v2 as cpVect, byval t as cpFloat ) as cpVect
	return cpvadd(cpvmult(v1, 1.0 - t), cpvmult(v2, t))
end function

function cpvnormalize( byval v as cpVect ) as cpVect
	return cpvmult(v, 1.0/cpvlength(v))
end function

function cpvnormalize_safe( byval v as cpVect ) as cpVect
	if v.x = 0.0 and v.y = 0.0 then
		return cpvzero
	end if
	return cpvnormalize(v)
end function

function cpvclamp( byval v as cpVect, byval length as cpFloat ) as cpVect
	if cpvdot(v, v) > (length * length) then
		return cpvmult( cpvnormalize(v), length )
	end if
	return v
end function

function cpvlerpconst( byval v1 as cpVect, byval v2 as cpVect, byval d as cpFloat ) as cpVect
	return cpvadd( v1, cpvclamp(cpvsub( v2, v1), d) )
end function

function cpvdist( byval v1 as cpVect, byval v2 as cpVect ) as cpFloat
	return cpvlength( cpvsub(v1, v2) )
end function

function cpvdistsq( byval v1 as cpVect, byval v2 as cpVect ) as cpFloat
	return cpvlengthsq( cpvsub(v1, v2) )
end function

function cpvnear( byval v1 as cpVect, byval v2 as cpVect, byval dist as cpFloat ) as integer
	return cpvdistsq( v1, v2 ) < (dist * dist)
end function

